home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / tools / gcc / gcc270_src.lha / gcc-2.7.0-amiga / config / tahoe / tahoe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-15  |  13.8 KB  |  566 lines

  1. /* Subroutines for insn-output.c for Tahoe.
  2.    Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21.  
  22. #include "config.h"
  23. #include "rtl.h"
  24. #include "regs.h"
  25. #include "hard-reg-set.h"
  26. #include "real.h"
  27. #include "insn-config.h"
  28. #include "conditions.h"
  29. #include "insn-flags.h"
  30. #include "output.h"
  31. #include "insn-attr.h"
  32.  
  33. /*
  34.  * File: output-tahoe.c
  35.  *
  36.  * Original port made at the University of Buffalo by Devon Bowen,
  37.  * Dale Wiles and Kevin Zachmann.
  38.  *
  39.  * Changes for HCX by Piet van Oostrum,
  40.  * University of Utrecht, The Netherlands (piet@cs.ruu.nl)
  41.  *
  42.  * Speed tweaks by Michael Tiemann (tiemann@lurch.stanford.edu).
  43.  *
  44.  * Mail bugs reports or fixes to:    gcc@cs.buffalo.edu
  45.  */
  46.  
  47.  
  48. /* On tahoe, you have to go to memory to convert a register
  49.    from sub-word to word.  */
  50.  
  51. rtx tahoe_reg_conversion_loc;
  52.  
  53. int
  54. extendable_operand (op, mode)
  55.      rtx op;
  56.      enum machine_mode mode;
  57. {
  58.   if ((GET_CODE (op) == REG
  59.        || (GET_CODE (op) == SUBREG
  60.        && GET_CODE (SUBREG_REG (op)) == REG))
  61.       && tahoe_reg_conversion_loc == 0)
  62.     tahoe_reg_conversion_loc = assign_stack_local (SImode, GET_MODE_SIZE (SImode));
  63.   return general_operand (op, mode);
  64. }
  65.  
  66. /* most of the print_operand_address function was taken from the vax    */
  67. /* since the modes are basically the same. I had to add a special case,    */
  68. /* though, for symbol references with offsets.                */
  69.  
  70. #include <stdio.h>
  71.  
  72. print_operand_address (file, addr)
  73.      FILE *file;
  74.      register rtx addr;
  75. {
  76.   register rtx reg1, reg2, breg, ireg;
  77.   rtx offset;
  78.   static char *reg_name[] = REGISTER_NAMES;
  79.  
  80.  retry:
  81.   switch (GET_CODE (addr))
  82.     {
  83.     case MEM:
  84.       fprintf (file, "*");
  85.       addr = XEXP (addr, 0);
  86.       goto retry;
  87.  
  88.     case REG:
  89.       fprintf (file, "(%s)", reg_name [REGNO (addr)]);
  90.       break;
  91.  
  92.     case PRE_DEC:
  93.       fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]);
  94.       break;
  95.  
  96.     case POST_INC:
  97.       fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]);
  98.       break;
  99.  
  100.     case PLUS:
  101.       reg1 = 0;    reg2 = 0;
  102.       ireg = 0;    breg = 0;
  103.       offset = 0;
  104.  
  105.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
  106.       && GET_CODE (XEXP (addr, 1)) == CONST_INT)
  107.     output_addr_const (file, addr);
  108.  
  109.       if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
  110.       && GET_CODE (XEXP (addr, 0)) == CONST_INT)
  111.     output_addr_const (file, addr);
  112.  
  113.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
  114.       || GET_CODE (XEXP (addr, 0)) == MEM)
  115.     {
  116.       offset = XEXP (addr, 0);
  117.       addr = XEXP (addr, 1);
  118.     }
  119.       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
  120.            || GET_CODE (XEXP (addr, 1)) == MEM)
  121.     {
  122.       offset = XEXP (addr, 1);
  123.       addr = XEXP (addr, 0);
  124.     }
  125.       if (GET_CODE (addr) != PLUS)
  126.     ;
  127.       else if (GET_CODE (XEXP (addr, 0)) == MULT)
  128.     {
  129.       reg1 = XEXP (addr, 0);
  130.       addr = XEXP (addr, 1);
  131.     }
  132.       else if (GET_CODE (XEXP (addr, 1)) == MULT)
  133.     {
  134.       reg1 = XEXP (addr, 1);
  135.       addr = XEXP (addr, 0);
  136.     }
  137.       else if (GET_CODE (XEXP (addr, 0)) == REG)
  138.     {
  139.       reg1 = XEXP (addr, 0);
  140.       addr = XEXP (addr, 1);
  141.     }
  142.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  143.     {
  144.       reg1 = XEXP (addr, 1);
  145.       addr = XEXP (addr, 0);
  146.     }
  147.       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  148.     {
  149.       if (reg1 == 0)
  150.         reg1 = addr;
  151.       else
  152.         reg2 = addr;
  153.       addr = 0;
  154.     }
  155.       if (offset != 0)
  156.     {
  157.       if (addr != 0) abort ();
  158.       addr = offset;
  159.     }
  160.       if (reg1 != 0 && GET_CODE (reg1) == MULT)
  161.     {
  162.       breg = reg2;
  163.       ireg = reg1;
  164.     }
  165.       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
  166.     {
  167.       breg = reg1;
  168.       ireg = reg2;
  169.     }
  170.       else if (reg2 != 0 || GET_CODE (addr) == MEM)
  171.     {
  172.       breg = reg2;
  173.       ireg = reg1;
  174.     }
  175.       else
  176.     {
  177.       breg = reg1;
  178.       ireg = reg2;
  179.     }
  180.       if (addr != 0)
  181.     output_address (offset);
  182.       if (breg != 0)
  183.     {
  184.       if (GET_CODE (breg) != REG)
  185.         abort ();
  186.       fprintf (file, "(%s)", reg_name[REGNO (breg)]);
  187.     }
  188.       if (ireg != 0)
  189.     {
  190.       if (GET_CODE (ireg) == MULT)
  191.         ireg = XEXP (ireg, 0);
  192.       if (GET_CODE (ireg) != REG)
  193.         abort ();
  194.       fprintf (file, "[%s]", reg_name[REGNO (ireg)]);
  195.     }
  196.       break;
  197.  
  198.     default:
  199.       output_addr_const (file, addr);
  200.     }
  201. }
  202.  
  203. /* Do a quick check and find out what the best way to do the */
  204. /* mini-move is. Could be a push or a move.....             */
  205.  
  206. static char *
  207. singlemove_string (operands)
  208.      rtx *operands;
  209. {
  210.   if (operands[1] == const0_rtx)
  211.       return "clrl %0";
  212.   if (push_operand (operands[0], SImode))
  213.     return "pushl %1";
  214.   return "movl %1,%0";
  215. }
  216.  
  217. /* given the rtx for an address, return true if the given */
  218. /* register number is used in the address somewhere.      */
  219.  
  220. regisused(addr,regnum)
  221. rtx addr;
  222. int regnum;
  223. {
  224.     if (GET_CODE(addr) == REG)
  225.         if (REGNO(addr) == regnum)
  226.             return (1);
  227.         else
  228.             return (0);
  229.  
  230.     if (GET_CODE(addr) == MEM)
  231.         return regisused(XEXP(addr,0),regnum);
  232.  
  233.     if ((GET_CODE(addr) == MULT) || (GET_CODE(addr) == PLUS))
  234.         return ((regisused(XEXP(addr,0),regnum)) ||
  235.                     (regisused(XEXP(addr,1),regnum)));
  236.  
  237.     return 0;
  238. }
  239.  
  240.  
  241. /* Given some rtx, traverse it and return the register used in a */
  242. /* index. If no index is found, return 0.             */
  243.  
  244. rtx
  245. index_reg(addr)
  246. rtx addr;
  247. {
  248.     rtx temp;
  249.  
  250.     if (GET_CODE(addr) == MEM)
  251.         return index_reg(XEXP(addr,0));
  252.  
  253.     if (GET_CODE(addr) == MULT)
  254.         if (GET_CODE(XEXP(addr,0)) == REG)
  255.             return XEXP(addr,0);
  256.         else
  257.             return XEXP(addr,1);
  258.  
  259.     if (GET_CODE(addr) == PLUS)
  260.         if (temp = index_reg(XEXP(addr,0)))
  261.             return temp;
  262.         else
  263.             return index_reg(XEXP(addr,1));
  264.  
  265.     return 0;
  266. }
  267.  
  268.  
  269. /* simulate the move double by generating two movl's. You have */
  270. /* to be careful about mixing modes here.               */
  271.  
  272. char *
  273. output_move_double (operands)
  274.      rtx *operands;
  275. {
  276.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP }
  277.     optype0, optype1;
  278.   rtx latehalf[2];
  279.   rtx shftreg0 = 0, shftreg1 = 0;
  280.   rtx temp0 = 0, temp1 = 0;
  281.   rtx addreg0 = 0, addreg1 = 0;
  282.   int dohighfirst = 0;
  283.  
  284.   /* First classify both operands. */
  285.  
  286.   if (REG_P (operands[0]))
  287.     optype0 = REGOP;
  288.   else if ((GET_CODE(operands[0])==MEM) && (shftreg0=index_reg(operands[0])))
  289.     optype0 = INDOP;
  290.   else if (offsettable_memref_p (operands[0]))
  291.     optype0 = OFFSOP;
  292.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) {
  293.     optype0 = PUSHOP;
  294.     dohighfirst++;
  295.   } else if (GET_CODE (operands[0]) == MEM)
  296.     optype0 = MEMOP;
  297.   else
  298.     optype0 = RNDOP;
  299.  
  300.   if (REG_P (operands[1]))
  301.     optype1 = REGOP;
  302.   else if ((GET_CODE(operands[1])==MEM) && (shftreg1=index_reg(operands[1])))
  303.     optype1 = INDOP;
  304.   else if (offsettable_memref_p (operands[1]))
  305.     optype1 = OFFSOP;
  306.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  307.     optype1 = POPOP; 
  308.   else if (GET_CODE (operands[1]) == MEM)
  309.     optype1 = MEMOP;
  310.   else if (CONSTANT_P (operands[1]))
  311.     optype1 = CNSTOP;
  312.   else
  313.     optype1 = RNDOP;
  314.  
  315.   /* set up for the high byte move for operand zero */
  316.  
  317.   switch (optype0) {
  318.  
  319.     /* if it's a register, just use the next highest in the */
  320.     /* high address move.                    */
  321.  
  322.     case REGOP  : latehalf[0] = gen_rtx (REG,SImode,REGNO(operands[0])+1);
  323.               break;
  324.  
  325.     /* for an offsettable address, use the gcc function to  */
  326.     /* modify the operand to get an offset of 4 higher for  */
  327.     /* the second move.                    */
  328.  
  329.     case OFFSOP : latehalf[0] = adj_offsettable_operand (operands[0], 4);
  330.               break;
  331.  
  332.     /* if the operand is MEMOP type, it must be a pointer    */
  333.     /* to a pointer. So just remember to increase the mem    */
  334.     /* location and use the same operand.            */
  335.  
  336.     case MEMOP  : latehalf[0] = operands[0];
  337.               addreg0 = XEXP(operands[0],0);
  338.               break;
  339.  
  340.     /* if we're dealing with a push instruction, just leave */
  341.     /* the operand alone since it auto-increments.        */
  342.  
  343.     case PUSHOP : latehalf[0] = operands[0];
  344.               break;
  345.  
  346.     /* YUCK! Indexed addressing!! If the address is considered   */
  347.     /* offsettable, go use the offset in the high part. Otherwise */
  348.     /* find what exactly is being added to the multiplication. If */
  349.     /* it's a mem reference, increment that with the high part   */
  350.     /* being unchanged to cause the shift. If it's a reg, do the */
  351.     /* same. If you can't identify it, abort. Remember that the  */
  352.     /* shift register was already set during identification.     */
  353.  
  354.     case INDOP  : if (offsettable_memref_p(operands[0])) {
  355.                latehalf[0] = adj_offsettable_operand(operands[0],4);
  356.                break;
  357.               }
  358.  
  359.               latehalf[0] = operands[0];
  360.  
  361.               temp0 = XEXP(XEXP(operands[0],0),0);
  362.                       if (GET_CODE(temp0) == MULT) {
  363.                temp1 = temp0;
  364.                temp0 = XEXP(XEXP(operands[0],0),1);
  365.               } else {
  366.                temp1 = XEXP(XEXP(operands[0],0),1);
  367.                if (GET_CODE(temp1) != MULT)
  368.                 abort();
  369.               }
  370.  
  371.               if (GET_CODE(temp0) == MEM)
  372.                addreg0 = temp0;
  373.               else if (GET_CODE(temp0) == REG)
  374.                addreg0 = temp0;
  375.               else
  376.                abort();
  377.  
  378.               break;
  379.  
  380.     /* if we don't know the operand type, print a friendly  */
  381.     /* little error message...   8-)            */
  382.  
  383.     case RNDOP  :
  384.     default     : abort();
  385.   }
  386.  
  387.   /* do the same setup for operand one */
  388.  
  389.   switch (optype1) {
  390.  
  391.     case REGOP  : latehalf[1] = gen_rtx(REG,SImode,REGNO(operands[1])+1);
  392.               break;
  393.  
  394.     case OFFSOP : latehalf[1] = adj_offsettable_operand (operands[1], 4);
  395.               break;
  396.  
  397.     case MEMOP  : latehalf[1] = operands[1];
  398.               addreg1 = XEXP(operands[1],0);
  399.               break;
  400.  
  401.     case POPOP  : latehalf[1] = operands[1];
  402.               break;
  403.  
  404.     case INDOP  : if (offsettable_memref_p(operands[1])) {
  405.                latehalf[1] = adj_offsettable_operand(operands[1],4);
  406.                break;
  407.               }
  408.  
  409.               latehalf[1] = operands[1];
  410.  
  411.               temp0 = XEXP(XEXP(operands[1],0),0);
  412.                       if (GET_CODE(temp0) == MULT) {
  413.                temp1 = temp0;
  414.                temp0 = XEXP(XEXP(operands[1],0),1);
  415.               } else {
  416.                temp1 = XEXP(XEXP(operands[1],0),1);
  417.                if (GET_CODE(temp1) != MULT)
  418.                 abort();
  419.               }
  420.  
  421.               if (GET_CODE(temp0) == MEM)
  422.                addreg1 = temp0;
  423.               else if (GET_CODE(temp0) == REG)
  424.                addreg1 = temp0;
  425.               else
  426.                abort();
  427.  
  428.               break;
  429.  
  430.     case CNSTOP :
  431.       if (GET_CODE (operands[1]) == CONST_DOUBLE)
  432.         split_double (operands[1], &operands[1], &latehalf[1]);
  433.       else if (CONSTANT_P (operands[1]))
  434.         latehalf[1] = const0_rtx;
  435.       else abort ();
  436.       break;
  437.  
  438.     case RNDOP  :
  439.     default     : abort();
  440.   }
  441.  
  442.  
  443.   /* double the register used for shifting in both of the operands */
  444.   /* but make sure the same register isn't doubled twice!       */
  445.  
  446.   if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
  447.     output_asm_insn("addl2 %0,%0", &shftreg0);
  448.   else {
  449.     if (shftreg0)
  450.         output_asm_insn("addl2 %0,%0", &shftreg0);
  451.     if (shftreg1)
  452.         output_asm_insn("addl2 %0,%0", &shftreg1);
  453.   }
  454.  
  455.   /* if the destination is a register and that register is needed in  */
  456.   /* the source addressing mode, swap the order of the moves since we */
  457.   /* don't want this destroyed til last. If both regs are used, not   */
  458.   /* much we can do, so abort. If these becomes a problem, maybe we   */
  459.   /* can do it on the stack?                          */
  460.  
  461.   if (GET_CODE(operands[0])==REG && regisused(operands[1],REGNO(operands[0])))
  462.     if (regisused(latehalf[1],REGNO(latehalf[0])))
  463.         8;
  464.     else
  465.         dohighfirst++;
  466.  
  467.   /* if we're pushing, do the high address part first. */
  468.  
  469.   if (dohighfirst) {
  470.  
  471.     if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  472.         output_asm_insn("addl2 $4,%0", &addreg0);
  473.     else {
  474.         if (addreg0)
  475.             output_asm_insn("addl2 $4,%0", &addreg0);
  476.         if (addreg1)
  477.             output_asm_insn("addl2 $4,%0", &addreg1);
  478.     }
  479.  
  480.     output_asm_insn(singlemove_string(latehalf), latehalf);
  481.  
  482.     if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  483.         output_asm_insn("subl2 $4,%0", &addreg0);
  484.     else {
  485.         if (addreg0)
  486.             output_asm_insn("subl2 $4,%0", &addreg0);
  487.         if (addreg1)
  488.             output_asm_insn("subl2 $4,%0", &addreg1);
  489.     }
  490.  
  491.     return singlemove_string(operands);
  492.   }
  493.  
  494.   output_asm_insn(singlemove_string(operands), operands);
  495.  
  496.   if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  497.     output_asm_insn("addl2 $4,%0", &addreg0);
  498.   else {
  499.     if (addreg0)
  500.         output_asm_insn("addl2 $4,%0", &addreg0);
  501.     if (addreg1)
  502.         output_asm_insn("addl2 $4,%0", &addreg1);
  503.   }
  504.  
  505.   output_asm_insn(singlemove_string(latehalf), latehalf);
  506.  
  507.   if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
  508.     output_asm_insn("subl2 $4,%0", &addreg0);
  509.   else {
  510.     if (addreg0)
  511.         output_asm_insn("subl2 $4,%0", &addreg0);
  512.     if (addreg1)
  513.         output_asm_insn("subl2 $4,%0", &addreg1);
  514.   }
  515.  
  516.   if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
  517.     output_asm_insn("shar $1,%0,%0", &shftreg0);
  518.   else {
  519.     if (shftreg0)
  520.         output_asm_insn("shar $1,%0,%0", &shftreg0);
  521.     if (shftreg1)
  522.         output_asm_insn("shar $1,%0,%0", &shftreg1);
  523.   }
  524.  
  525.   return "";
  526. }
  527.  
  528.  
  529. /* This checks if a zero_extended cmp[bw] can be replaced by a sign_extended
  530.    cmp[bw]. This can be done if the operand is a constant that fits in a
  531.    byte/word or a memory operand. Besides that the next instruction must be an
  532.    unsigned compare. Some of these tests are done by the machine description */
  533.  
  534. int
  535. tahoe_cmp_check (insn, op, max)
  536. rtx insn, op; int max;
  537. {
  538.     if (GET_CODE (op) == CONST_INT
  539.     && ( INTVAL (op) < 0 || INTVAL (op) > max ))
  540.     return 0;
  541.     {
  542.     register rtx next = NEXT_INSN (insn);
  543.  
  544.     if ((GET_CODE (next) == JUMP_INSN
  545.        || GET_CODE (next) == INSN
  546.        || GET_CODE (next) == CALL_INSN))
  547.         {
  548.         next = PATTERN (next);
  549.         if (GET_CODE (next) == SET
  550.             && SET_DEST (next) == pc_rtx
  551.             && GET_CODE (SET_SRC (next)) == IF_THEN_ELSE)
  552.             switch (GET_CODE (XEXP (SET_SRC (next), 0)))
  553.             {
  554.             case EQ:
  555.             case NE:
  556.             case LTU:
  557.             case GTU:
  558.             case LEU:
  559.             case GEU:
  560.                 return 1;
  561.             }
  562.         }
  563.     }
  564.     return 0;
  565. }
  566.